package com.morgan.basemodule.fragment

import android.os.Bundle
import androidx.fragment.app.Fragment
import androidx.fragment.app.FragmentManager
import com.morgan.basemodule.ext.isEmpty
import com.morgan.basemodule.ext.runOnMain

/**
 *description：fragment show hide工具
 *<br>author：caowugao
 *<br>time：2021/3/30 0030 17:30
 */
class FragShowHideTool(private val fragManager: FragmentManager, private val containerId : Int){
    val tags : ArrayList<String> by lazy { ArrayList() }
    val frags : ArrayList<Fragment> by lazy { ArrayList() }
    private val lock : Any by lazy { Any() }
    private var currShowingIndex = -1
    private var restoreShowingIndex = -1
    private val showingIndexKey = "showingIndexKey"

    fun size() = synchronized(lock) {frags.size}

    fun remove(tag : String) {
        val index = synchronized(lock) {tags.indexOf(tag)}
        removeAt(index)
    }

    fun removeAt(index : Int) {
        if (index >= 0 && index < size()) {
            synchronized(lock) {
                tags.removeAt(index)
                frags.removeAt(index)
            }
        }
    }

    fun add(tag : String, fragment: Fragment) {
        add(-1, tag, fragment)
    }

    fun addAll(outTags : List<String>, outFrags : List<Fragment>) {
        if (isEmpty(outTags) || isEmpty(outFrags)|| outTags.size != outFrags.size) {
            return
        }
        synchronized(lock) {
            tags.addAll(outTags)
            frags.addAll(outFrags)
        }
    }

    fun add(index : Int, tag : String, fragment: Fragment) {
        if (index == -1) {
            synchronized(lock) {
                tags.add(tag)
                frags.add(fragment)
            }
            return
        }
        if (index >= 0 && index < size()) {
            synchronized(lock) {
                tags.add(index, tag)
                frags.add(index, fragment)
            }
        }
    }

    fun replace(index : Int, tag : String, fragment: Fragment) {
        if (index >= 0 && index < size()) {
            synchronized(lock) {
                add(index, tag, fragment)
                removeAt(index)
            }
        }
    }

    fun clear() = synchronized(lock) {tags.clear(); frags.clear()}

    fun onCreate(outTags : List<String>, outFrags : List<Fragment>, savedInstanceState: Bundle?) {
        onRestoreInstanceState(outTags, outFrags, savedInstanceState)
    }

    fun onSaveInstanceState(savedInstanceState: Bundle?) {
        savedInstanceState?:return
        if (size() <= 0) {
            return
        }

//        synchronized(lock) {
//            val rang = 0 until size()
//            for (i in rang) {
//                fragManager.putFragment(savedInstanceState, tags[i], frags[i])
//            }
//        }

        savedInstanceState.putInt(showingIndexKey, currShowingIndex)
    }

    fun onRestoreInstanceState(
        outTags: List<String>,
        outFrags: List<Fragment>,
        savedInstanceState: Bundle?
    ) {
        if (isEmpty(outTags) || isEmpty(outFrags)|| outTags.size != outFrags.size || size() > 0) {
            return
        }
        if (savedInstanceState == null) {
            addAll(outTags, outFrags)
            return
        }

        restoreShowingIndex = savedInstanceState.getInt(showingIndexKey, currShowingIndex)
//        outTags.forEach {tag ->
//            try {
////                val frag = fragManager.getFragment(savedInstanceState, tag)!!
//                val frag = fragManager.findFragmentByTag(tag)!!
//                add(tag, frag)
//            } catch (e : Throwable) {
//                e.printStackTrace()
//            }
//        }
        val rang = outTags.indices
        for (i in rang) {
            val tag = outTags[i]
            try {
                val frag = fragManager.findFragmentByTag(tag)!!
                add(tag, frag)
            } catch (e : Throwable) {
                e.printStackTrace()
                add(tag, outFrags[i])
            }
        }

    }


    fun showByRestore() : Boolean = show(restoreShowingIndex)

    fun show(index : Int) : Boolean {
        if (index < 0 || index >= size() || currShowingIndex == index) {
            return false
        }
        synchronized(lock) {
            currShowingIndex = index
            val tag = tags[index]
            val frag = frags[index]
            val transaction = fragManager.beginTransaction()
            frags.forEach {itemFrag ->
                if (itemFrag != frag) {
                    if (itemFrag.isAdded) {
                        transaction.hide(itemFrag)
                    }
                }
            }

            if (!frag.isAdded) {
                transaction.add(containerId, frag, tag)
            } else {
                transaction.show(frag)
            }
            transaction.commitAllowingStateLoss()
        }
        return true
    }

}